package com.jwsoft.manager.core.task.address;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.engine.assistant.core.utils.SessionUtil;
import com.bifang.engine.cache.redis.RedisHelper;
import com.bifang.engine.protect.core.annotation.NoSignCrypto;
import com.github.pagehelper.PageHelper;
import com.jwsoft.manager.common.constant.EduCache;
import com.jwsoft.manager.common.enums.HandleStatusEnum;
import com.jwsoft.manager.common.enums.MatchingStatusEnum;
import com.jwsoft.manager.common.vo.eduAddress.EduAddressVO;
import com.jwsoft.manager.common.vo.eduAddressTree.AddressReqVO;
import com.jwsoft.manager.core.dao.model.EduAddress;
import com.jwsoft.manager.core.dao.model.EduAddressTreeInitial;
import com.jwsoft.manager.core.dao.service.EduAddressService;
import com.jwsoft.manager.core.integration.EduAddressIntegration;
import com.jwsoft.manager.core.integration.eduAddressTree.EduAddressTreeIntegration;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 地址格式化脚本
 *
 * @author fangs
 */
@Component
@Slf4j
public class AddressFormatXxlJob {

    @Autowired
    private EduAddressService eduAddressService;
    @Autowired
    private EduAddressIntegration eduAddressIntegration;
    @Autowired
    private EduAddressTreeIntegration addressTreeIntegration;
    @Autowired
    private RedisHelper redisHelper;
    //最大的处理数量
    private static final Integer HANDLE_MAX_COUNT = 100000;

    @XxlJob("addressFormatJobHandler")
    public void addressFormatJobHandler() {
        String redisKey= EduCache.EDU_DATA_TASK_DETAIL+"addressFormatJobHandler";
        boolean lock = false;
        lock = redisHelper.hasKey(redisKey);
        if (lock) {
            XxlJobHelper.log("XXL-JOB, addressFormatJobHandler, 已经在执行中");
            throw new AppException("XXL-JOB, addressFormatJobHandler, 已经在执行中,请稍后再试！");
        }else{
            //获取不到，就设置锁
            redisHelper.set(redisKey, true, 1800);
            try {
                // 执行任务
                XxlJobHelper.log("XXL-JOB, addressFormatJobHandler");
                log.info("执行地址格式化开始");
                this.passeAddressFormat();
            } finally {
                // 释放锁
                redisHelper.del(redisKey);
            }
            log.info("执行地址格式化结束");
            XxlJobHelper.log("XXL-JOB, 执行地址格式化结束");
        }
    }

    private void passeAddressFormat() {
        AtomicInteger handleCount = new AtomicInteger(0);
        int count = 0;
        do {
            //查询出matchingStatus = 0的数据， 再去比对 handleStatus
            QueryWrapper<EduAddress> queryWrapper = new QueryWrapper<>();
            //只查出来处理状态 = 0 或 1的数据
            List<String> handleList = new ArrayList<>();
            handleList.add(HandleStatusEnum.NODO.getType());
            handleList.add(HandleStatusEnum.success.getType());
            queryWrapper.lambda().select(EduAddress::getAddressId,
                            EduAddress::getHandleStatus,
                            EduAddress::getMatchingStatus,
                            EduAddress::getAddressName,
                            EduAddress::getAddressTreeId)
                    .eq(EduAddress::getFictitious, BoolEnum.FALSE.getType())
                    .in(EduAddress::getHandleStatus,handleList)
                    .and(wrapper -> wrapper
                            //查出matchingStatus = 0 或者为null的地址信息
                            .eq(EduAddress::getMatchingStatus, MatchingStatusEnum.NODO.getType())
                            .or()
                            .isNull(EduAddress::getMatchingStatus)
                    );
            PageHelper.startPage(0, 2000);
            List<EduAddress> list = eduAddressService.list(queryWrapper);
            if (CollectionUtils.isEmpty(list)) {
                break;
            }
            for (EduAddress eduAddress : list) {
                count = handleCount.incrementAndGet();
                //1.如果handleStatus = 1 表示地址解析过了
                if (HandleStatusEnum.success.getType().equals(eduAddress.getHandleStatus())) {
                    if (eduAddress.getAddressTreeId() != null){
                        try {
                            addressTreeIntegration.matchSchoolAndSave(eduAddress);
                        } catch (Exception e) {
                            // 处理异常情况，例如记录日志
                            XxlJobHelper.log("处理地址：【"+eduAddress.getAddressId()+"】"+"地址匹配学区过程中出现异常：" + e.getMessage(), e);
                        }
                    }
                } else {
                    //2.如果handleStatus = 0 表示地址未解析过 ，重新解析 在匹配学区
                    AddressReqVO addressReqVO = new AddressReqVO();
                    addressReqVO.setAddressId(eduAddress.getAddressId());
                    addressReqVO.setHandleStatus(eduAddress.getHandleStatus());
                    try {
                        addressTreeIntegration.newAddressParse(addressReqVO);
                        addressTreeIntegration.saveAddressSchoolAudit(addressReqVO);
                    } catch (Exception e) {
                        // 处理异常情况，例如记录日志
                        XxlJobHelper.log("处理地址：【"+eduAddress.getAddressId()+"】"+"重新解析并匹配学区过程中出现异常：" + e.getMessage(), e);
                    }
                }
            }
            //处理完成一个limit之后， 判断是否处理到最后一页数据
            if ( 2000 > list.size()) {
                break;
            }
            //最大处理数量 超过就直接退出
            if (count >= HANDLE_MAX_COUNT){
                break;
            }
        }while (true);
    }

    private void formatAddress() {
        String minAddressId = null;
        //优先格式化已经匹配到学区的地址
        String matchingStatus = MatchingStatusEnum.SUCCESS.getType();
        do {
            QueryWrapper<EduAddress> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().select(EduAddress::getAddressId, EduAddress::getAddressName)
                    .eq(EduAddress::getStatus, BoolEnum.TRUE.getType())
                    .eq(EduAddress::getFictitious, BoolEnum.FALSE.getType())
                    .and(wrapper -> wrapper
                            .eq(EduAddress::getHandleStatus, HandleStatusEnum.NODO.getType())
                            .or()
                            .isNull(EduAddress::getHandleStatus)
                    );
            if (MatchingStatusEnum.NODO.getType().equals(matchingStatus)) {
                String finalMatchingStatus = matchingStatus;
                queryWrapper.lambda().and(q -> q
                        .eq(EduAddress::getMatchingStatus, finalMatchingStatus)
                        .or()
                        .isNull(EduAddress::getMatchingStatus)
                );
            } else {
                queryWrapper.lambda().eq(EduAddress::getMatchingStatus, matchingStatus);
            }
            if (minAddressId != null) {
                queryWrapper.lambda().gt(EduAddress::getAddressId, minAddressId);
            }
            PageHelper.startPage(0, 2000);
            List<EduAddress> list = eduAddressService.list(queryWrapper);
            if (CollectionUtils.isEmpty(list)) {
                //优先格式化已经匹配到学区的地址
                //匹配到学区的地址格式化完了后，继续格式化未匹配学区的地址
                if (MatchingStatusEnum.SUCCESS.getType().equals(matchingStatus)) {
                    matchingStatus = MatchingStatusEnum.NODO.getType();
                    minAddressId = null;
                    continue;
                } else {
                    break;
                }
            }
            //取出每次查询最大的主键，作为下次查询的最小边界
            minAddressId = list.get(list.size() - 1).getAddressId();
            //遍历格式化地址
            for (EduAddress eduAddress : list) {
                EduAddressVO eduAddressVO = Convert.convert(EduAddressVO.class, eduAddress);
                eduAddressIntegration.parseAddressForJob(eduAddressVO);
            }

        } while (true);
    }


}
